#include "../TestFramework/RegistryManager.h"
#include "../TestFramework/TestString.h"
#include "RegistryTests.h"

namespace
{
    class RegistryKeysEnumerator : public TestFramework::KeysEnumerator
    {
    public:
        RegistryKeysEnumerator()
            : KeysCount(0)
        {
        }

        virtual void ProcessKey(TestFramework::RegistryKey& key)
        {
            TestFramework::KeyInfo info = key.GetInfo();
            KeysCount += info.SubKeysCount;
        }

        int GetResult() const
        {
            return KeysCount;
        }

    private:
        int KeysCount;
    };

    class RegistryValueEnumerator : public TestFramework::ValueEnumerator
    {
    public:
        RegistryValueEnumerator()
            : ValuesCount(0)
        {
        }

        virtual void ProcessValue(TestFramework::RegistryValue& value)
        {
            ValuesCount++;
        }

        int GetResult() const
        {
            return ValuesCount;
        }

    private:
        int ValuesCount;
    };

    TEST_CASE(TestRegistryOpenRoots)
    {
        TestFramework::RegistryKey hkcr = TestFramework::GetClassesRoot();
        TestFramework::RegistryKey hkcc = TestFramework::GetCurrentConfig();
        TestFramework::RegistryKey hkcu = TestFramework::GetCurrentUser();
        TestFramework::RegistryKey hklm = TestFramework::GetLocalMachine();
        TestFramework::RegistryKey hku = TestFramework::GetUsers();
    }
    
    TEST_CASE(TestRegistryOpenCustomKey)
    {
        TestFramework::RegistryKey hklm = TestFramework::GetCurrentUser();
        CHECK_EXCEPTION_ABSENT(hklm[L"Software"][L"Microsoft"][L"Windows"]);
    }

    TEST_CASE(TestRegistryOpenComplexPath)
    {
        TestFramework::RegistryKey hklm = TestFramework::GetLocalMachine();
        CHECK_EXCEPTION_ABSENT(hklm[L"Software\\Microsoft"]);
    }

    TEST_CASE(TestRegistryKeyComplexPath)
    {
        TestFramework::RegistryKey hklm(HKEY_LOCAL_MACHINE, L"Software\\Microsoft");
    }

    TEST_CASE(TestRegistryAbsentKeyCheck)
    {
        TestFramework::RegistryKey hklm = TestFramework::GetLocalMachine();
        CHECK_EXCEPTION_OCCURRENCE(hklm[L"Hello"]);
    }

    TEST_CASE(TestRegistryInfoGetting)
    {
        TestFramework::RegistryKey hklm = TestFramework::GetLocalMachine();
        CHECK_EXCEPTION_ABSENT(hklm.GetInfo());
    }

    TEST_CASE(TestKeyCreating)
    {
        TestFramework::RegistryKey hcu = TestFramework::GetCurrentUser(TestFramework::WRITE_ONLY);
        CHECK_EXCEPTION_ABSENT(hcu[L"Software"].CreateKey(L"TestFramework"));
    }

    TEST_CASE(TestRegistryBinaryValueCreating)
    {
        TestFramework::RegistryKey hcu = TestFramework::GetCurrentUser(TestFramework::ALL_ACCESS);
        TestFramework::RegistryKey target = hcu[L"Software"].CreateKey(L"TestFramework");
        TestFramework::TestAutoPtr<TestFramework::RegistryValue> value = target.CreateValue(L"TestValue");
        TestFramework::TestVector<byte> source(5);
        for (int i = 0; i < 5; ++i)
        {
            source[i] = i;
        }

        value->Set(source);
        TestFramework::TestVector<byte> test;
        value->Get(test);
        CHECK(test == source);
    }

    TEST_CASE(TestRegistryStringValueCreating)
    {
        TestFramework::RegistryKey target = TestFramework::GetCurrentUser(
            TestFramework::ALL_ACCESS)[L"Software"].CreateKey(L"TestFramework");

        TestFramework::TestAutoPtr<TestFramework::RegistryValue> valueW = target.CreateValue(L"TestStringW");
        TestFramework::TestWString sourceW(L"hello");
        valueW->Set(sourceW);
        TestFramework::TestWString targetW;
        valueW->Get<TestFramework::TestWString>(targetW);
        CHECK(targetW == sourceW);
    }

    TEST_CASE(TestRegistryNumbersValueCreating)
    {
        TestFramework::RegistryKey target = TestFramework::GetCurrentUser(
            TestFramework::ALL_ACCESS)[L"Software"].CreateKey(L"TestFramework");

        TestFramework::TestAutoPtr<TestFramework::RegistryValue> value = target.CreateValue(L"TestDword");
        DWORD sourceValue = 10;
        value->Set(sourceValue);
        DWORD targetValue;
        value->Get(targetValue);
        CHECK(sourceValue == targetValue);

        TestFramework::TestAutoPtr<TestFramework::RegistryValue> valueL = target.CreateValue(L"TestLong");
        long long sourceValueL = 1234567890;
        valueL->Set(sourceValueL);
        long long targetValueL;
        valueL->Get(targetValueL);
        CHECK(sourceValueL == targetValueL);
    }

    TEST_CASE(TestRegistryValuesDeleting)
    {
        TestFramework::RegistryKey target = TestFramework::GetCurrentUser(
            TestFramework::ALL_ACCESS)[L"Software"].CreateKey(L"TestFramework");

        TestFramework::TestAutoPtr<TestFramework::RegistryValue> value = target.CreateValue(L"Deleting");
        DWORD sourceValue = 10;
        value->Set(sourceValue);
        CHECK_EXCEPTION_ABSENT(target.DeleteValue(L"Deleting"));
    }

    TEST_CASE(TestRegistryKeyDeleting)
    {
        TestFramework::RegistryKey target = TestFramework::GetCurrentUser(TestFramework::ALL_ACCESS)[L"Software"];
        CHECK_EXCEPTION_ABSENT(target.DeleteKey(L"TestFramework"));
    }

    TEST_CASE(TestRegistryKeysEnumeration)
    {
        RegistryKeysEnumerator enumerator;
		TestFramework::RegistryKey microsoft = TestFramework::GetCurrentUser(TestFramework::READ_ONLY)[L"Software"];
        microsoft.EnumerateKeys(enumerator);
        int result = enumerator.GetResult();
        CHECK(result != 0);
    }

    TEST_CASE(TestRegistryValuesEnumeration)
    {
        RegistryValueEnumerator enumerator;
        TestFramework::RegistryKey explorer = TestFramework::GetCurrentUser(
            TestFramework::ALL_ACCESS)[L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"];

        explorer.EnumerateValues(enumerator);
        int result = enumerator.GetResult();
        CHECK(result != 0);
    }

    START_TEST_SUITE(RegistryTest, "Registry test")
    {
        REGISTER_TEST(TestRegistryOpenRoots);
        REGISTER_TEST(TestRegistryOpenCustomKey);
        REGISTER_TEST(TestRegistryOpenComplexPath);
        REGISTER_TEST(TestRegistryKeyComplexPath);
        REGISTER_TEST(TestRegistryAbsentKeyCheck);
        REGISTER_TEST(TestRegistryInfoGetting);
        REGISTER_TEST(TestKeyCreating);
        REGISTER_TEST(TestRegistryBinaryValueCreating);
        REGISTER_TEST(TestRegistryStringValueCreating);
        REGISTER_TEST(TestRegistryNumbersValueCreating);
        REGISTER_TEST(TestRegistryValuesDeleting);
        REGISTER_TEST(TestRegistryKeyDeleting);
        REGISTER_TEST(TestRegistryKeysEnumeration);
        //REGISTER_TEST(TestRegistryValuesEnumeration);
    }
    FINISH_TEST_SUITE
}

namespace Tests
{
    TestFramework::UnitTestPtr CreateRegistryTester()
    {
        CREATE_SUITE(RegistryTest)
    }
}
